///////////////////////////////////////////////////////////////////////////
// 
// AutoUpdater
// 
// Copyright 2008 ARTSTAFF CO.,LTD. 
// All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////
package jp.co.artstaff.updater
{
import flash.desktop.Updater;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.URLStream;
import flash.utils.ByteArray;

import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
import mx.utils.Base64Encoder;

/**
 * AutoUpdater
 * 
 */
public class AutoUpdater extends EventDispatcher
{
    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    // サービス（バージョン情報取得用）
    //----------------------------------
    private var _versionHttpService:HTTPService = new HTTPService();;

    // 最新バージョン（文字列）
    private var _latestVersionStr:String;

    //----------------------------------
    // サービス（アプリケーション取得用）
    //----------------------------------
    private var _appDownloadURLRequest:URLRequest;
    private var _appDownloadURLStream:URLStream;

    //----------------------------------
    // 設定情報
    //----------------------------------
    private var _config:AutoUpdateConfig;

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------
    /**
     * Constructor 
     * 
     */
    public function AutoUpdater(config:AutoUpdateConfig):void
    {
        var base64encoder:Base64Encoder;

        _config = config;
        
        // サービス設定（バージョン情報取得用）
        _versionHttpService.url 
            = getVersionDefineFileUrl();
        if(_config.basicAuthId != null)
        {
            // Basic認証有りの場合
            base64encoder = new Base64Encoder();
            base64encoder.encode(
                _config.basicAuthId 
                + ":" + _config.basicAuthPassword);
            _versionHttpService.headers 
                = {Authorization:"Basic "+base64encoder.toString()};
        }
        _versionHttpService.resultFormat = "e4x";
        _versionHttpService.addEventListener(
            ResultEvent.RESULT,_completeGetVersionHandler);
        _versionHttpService.addEventListener(
            FaultEvent.FAULT,_faultGetVersionHandler);

        // サービス設定（アプリケーション取得用）
        _appDownloadURLRequest 
            = new URLRequest(getApplicationFileUrl());
        if(_config.basicAuthId != null)
        {
            // Basic認証有りの場合
            base64encoder = new Base64Encoder();
            base64encoder.encode(
                _config.basicAuthId
                    + ":" + _config.basicAuthPassword);
            _appDownloadURLRequest.requestHeaders.push(
                new URLRequestHeader(
                    "Authorization"
                    ,"Basic " + base64encoder.toString()));
        }
        _appDownloadURLStream = new URLStream();
        _appDownloadURLStream.addEventListener(
            Event.COMPLETE,_completeLoadAirFileHandler);
        _appDownloadURLStream.addEventListener(
            IOErrorEvent.IO_ERROR,_faultLoadAirFileHandler);
        _appDownloadURLStream.addEventListener(
            SecurityErrorEvent.SECURITY_ERROR,_faultLoadAirFileHandler);
    }

    /**
     *　バージョン情報をダウンロードサーバから取得
     * 
     */
    public function getVersion():void
    {
        // サービス呼び出し
        _versionHttpService.send();
    }

    /**
     * バージョンチェック
     * 
     * @param currentVer 現バージョン番号（数値として解釈可能な文字列）
     * @return 現バージョンが最新バージョンかどうか
     * 
     */
    public function isLatestApp(currentVer:String):Boolean
    {
        if(Number(currentVer) < Number(_latestVersionStr))
            return false;
        else
            return true;
    }

    /**
     * 最新バージョン番号取得
     * 
     * @return 最新バージョン番号 
     * 
     */
    public function getLatestVersionStr():String
    {
        return _latestVersionStr;
    }

    /**
     * AIRファイルのロード
     * 
     */
    public function loadAirFile():void 
    {
        // サービス呼び出し
        _appDownloadURLStream.load(_appDownloadURLRequest);
    }

    /**
     * バージョン定義ファイルURL取得
     *  
     * @return バージョン定義ファイルURL 
     * 
     */
    public function getVersionDefineFileUrl():String
    {
        return "http://"+ _config.updateServerDomain 
                    +"/"+ _config.updateServerPath
                    +"/"+ _config.versionDefineFileName;
    }

    // アプリケーションファイルURL取得
    private function getApplicationFileUrl():String
    {
        return "http://"+ _config.updateServerDomain 
                    +"/"+ _config.updateServerPath
                    +"/"+ _config.applicationFileName;
    }

    //--------------------------------------------------------------------------
    //
    //  Event handlers
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    // 最新バージョン番号取得完了
    //----------------------------------
    private function _completeGetVersionHandler(event:ResultEvent):void
    {
        var resultxml:XML = new XML(event.result);
        _latestVersionStr = resultxml.version;
        
        // イベントトリガ（バージョン番号取得成功）
        this.dispatchEvent(
            new AutoUpdateEvent(AutoUpdateEvent.GET_VERSION_COMPLETE));
    }

    //----------------------------------
    // 最新バージョン番号取得失敗
    //----------------------------------
    private function _faultGetVersionHandler(event:FaultEvent):void
    {
        // イベントトリガ（最新バージョン番号取得失敗）
        this.dispatchEvent(
            new AutoUpdateEvent(AutoUpdateEvent.GET_VERSION_FAULT));
    }
    
    //----------------------------------
    // AIRファイルダウンロード失敗
    //----------------------------------
    private function _faultLoadAirFileHandler(event:Event):void
    {
        // イベントトリガ（Airファイル更新（DLor書き込み)失敗）
        this.dispatchEvent(
            new AutoUpdateEvent(AutoUpdateEvent.UPDATE_AIRFILE_FAULT));
    }

    //----------------------------------
    // AIRファイルダウンロード成功
    //----------------------------------
    private function _completeLoadAirFileHandler(event:Event):void
    {
        // ダウンロードしたファイルを、ローカルディスクのテンポラリ領域へ保存
        var fileData:ByteArray = new ByteArray();
        _appDownloadURLStream.readBytes(
            fileData
            , 0
            , _appDownloadURLStream.bytesAvailable);

        var file:File 
            = File.applicationStorageDirectory.resolvePath(
                _config.applicationFileName);
        var fileStream:FileStream = new FileStream();
        fileStream.addEventListener(Event.CLOSE, _completeWriteFileHandler);
        fileStream.addEventListener(IOErrorEvent.IO_ERROR, _faultWriteFileHandler);
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(fileData, 0, fileData.length);
        fileStream.close();
    }
    
    //----------------------------------
    // ローカルディスクへの保存成功
    //----------------------------------
    private function _completeWriteFileHandler(event:Event):void
    {
        // アプリケーションのアップデート
        var updater:Updater = new Updater();
        var file:File 
            = File.applicationStorageDirectory.resolvePath(
                _config.applicationFileName);
        updater.update(file, _latestVersionStr);
    }

    //----------------------------------
    // ローカルディスクへの保存失敗
    //----------------------------------
    private function _faultWriteFileHandler(event:IOErrorEvent):void 
    {
        // イベントトリガ（Airファイル更新（DLor書き込み)失敗）
        this.dispatchEvent(
            new AutoUpdateEvent(AutoUpdateEvent.UPDATE_AIRFILE_FAULT));
    }

}
}